package de.ifgi;

import android.util.Log;
import Jama.Matrix;

public class Transformation {
	private static final double minX = 404449.791;
	private static final double maxX = 404490.942;
	private static final double minY = 5755385.608;
	private static final double maxY = 5755426.998;
	private static final String tag = "OIL";

	private Point pt1;
	private Point pt2;
	private double mapWidth;
	private double mapHeight;

	public Transformation(Point pt1, Point pt2, double mapWidth, double mapHeight) {
		this.pt1 = pt1;
		this.pt2 = pt2;
		this.mapWidth = mapWidth;
		this.mapHeight = mapHeight;
	}
	
	/**
	 * Returns the pixel coordinates of a point in a georeferenced map.
	 * @param p The georeferenced coordinates (in UTM).
	 * @return The pixel coordinates.
	 */
	public Point toPixel(Point p) {
		double x = p.getX();
		double y = p.getY();
		
		double tmpX = ((x-minX) * mapWidth) / (maxX-minX);
        double tmpY = mapHeight - (((y-minY) * mapHeight) / (maxY-minY));
        Log.d(tag, "x,y="+x+","+y+" tmpX,tmpY="+tmpX+","+tmpY);
        
        Point pRes = new Point(tmpX, tmpY);
        return pRes;		
	}
	
	/**
	 * Returns the transformation parameters needed to transform a-somehow-distorted 
	 * georeferenced map to a-correctly-displayed map.
	 * @return The transformation parameters.
	 */
    public double[] getTransformationParams() {
    	Point p1 = toPixel(pt1);
    	Point p2 = toPixel(pt2);
    	
    	double[][] arrPts = {{p1.getX(),p1.getY(),1,0}, {p1.getY(),-p1.getX(),0,1}, 
    			{p2.getX(),p2.getY(),1,0}, {p2.getY(),-p2.getX(),0,1}};
    	Matrix mPts = new Matrix(arrPts);
    	
        double[] arrPxs = {0,0,0,mapHeight};
        Matrix mPxs = new Matrix(arrPxs, 4);
        
        Matrix res = mPts.inverse().times(mPxs);
        double[] params = res.getColumnPackedCopy();
    	return params;
    }
    
    /**
     * Returns the pixel coordinates of a point in a-correctly-displayed map.
     * @param p The pixel coordinates (in a-somehow-distorted frame).
     * @return The pixel coordinates (in a-correctly-displayed frame).
     */
    public Point transformPixel(Point p) {
    	double[] params = getTransformationParams();
    	// x' = Ax + B
        double[][] A = {{params[0], params[1]}, {-params[1], params[0]}};
        Matrix mA = new Matrix(A);
        
        double[] B = {params[2], params[3]};
        Matrix mB = new Matrix(B, 2);
        
        Point userPos = toPixel(p);
        double[] arrUserPos = {userPos.getX(), userPos.getY()};
        Matrix mUserPos = new Matrix(arrUserPos, 2);
        
        Matrix res = mA.times(mUserPos).plus(mB);
        double[] arrRes = res.getColumnPackedCopy();
        
        Point pRes = new Point(arrRes[0], arrRes[1]);
		return pRes;
    }

}
